package java学习.leetcode.editor.cn;


import java.util.*;
import java.util.zip.ZipEntry;

/**
 * @author 刘世锦
 * 2022-11-13 23:37:53	 当前时间
 */
//给你一个整数数组 nums 和一个整数 k ，请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 
//
// 
//
// 示例 1: 
//
// 
//输入: nums = [1,1,1,2,2,3], k = 2
//输出: [1,2]
// 
//
// 示例 2: 
//
// 
//输入: nums = [1], k = 1
//输出: [1] 
//
// 
//
// 提示： 
//
// 
// 1 <= nums.length <= 105 
// k 的取值范围是 [1, 数组中不相同的元素的个数] 
// 题目数据保证答案唯一，换句话说，数组中前 k 个高频元素的集合是唯一的 
// 
//
// 
//
// 进阶：你所设计算法的时间复杂度 必须 优于 O(n log n) ，其中 n 是数组大小。 
// Related Topics 数组 哈希表 分治 桶排序 计数 快速选择 排序 堆（优先队列） 
// 👍 1383 👎 0

public class 前K个高频元素{
	public static void main(String[] args) {
		Solution solution = new 前K个高频元素().new Solution();
		int[] nums = {1,1,1,2,2,3};
//		int[] nums = {1,2,2,3,3,3};
		int  k = 2;
		solution.topKFrequent(nums,k);
	}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
//输入: nums = [1,1,1,2,2,3], k = 2
//输出: [1,2]

	/**
	 *  | 3 2 1
	 *    1 2 3
	 */
//	最小堆
	public int[] topKFrequent(int[] nums, int k) {
		int[] dp = new int[k];
		HashMap<Integer, Integer> map = new HashMap<>();
		for (int i = 0; i < nums.length; i++) {
			map.put(nums[i],map.getOrDefault(nums[i],0)+1);
		}
		/**
		 *  小顶堆
		 *  每次都将最小的出队
		 *  留下的自然是最大的
		 */
		PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				return map.get(o1)-map.get(o2);
			}
		});
		Set<Integer> keySet = map.keySet();
		for (Integer em : keySet) {
//			队列size满足k个
			if (queue.size()<k){
				queue.offer(em);
//				新来的出现次数>队顶
			}else if (map.get(queue.peek())<map.get(em)){
				queue.poll();
				queue.offer(em);
			}
		}
		int i = 0;
		 while (queue.size()>0){
		 	dp[i++] = queue.poll();
		 }
		System.out.println(Arrays.toString(dp));
		return dp;


	}
//	比较器
	public int[] topKFrequent1(int[] nums, int k) {
		int[] dp = new int[k];
		HashMap<Integer, Integer> map = new HashMap<>();
		for (int i = 0; i < nums.length; i++) {
			map.put(nums[i],map.getOrDefault(nums[i],0)+1);
		}
//		为什么用Entry： Entry可以同时获得其key和value。
		ArrayList<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());
		list.sort((o1, o2) -> o2.getValue() - o1.getValue());
		for (int i = 0; i < k; i++) {
			Map.Entry<Integer, Integer> entry = list.get(i);
			dp[i] = entry.getKey();
		}

		return dp;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

}
